﻿using System;
using System.IO;
using System.Xml.Serialization;
using System.Xml.XPath;
using System.Xml;
using System.Web;

namespace HyperCrunch.Druid.Sample
{

    public class ProductModel
    {

        private ProductCollection _products;
        private static string DATA_FILE_FOLDER = "~/DesktopModules/HyperCrunch/HyperCrunch.Druid.Sample/Data/";
        private static string IMAGE_FILE_FOLDER = DATA_FILE_FOLDER + "images/";
        private static string IMAGE_FILE_EXTENSION = ".jpg";
        private static string DATA_FILE = "products.config";

        public ProductCollection Products
        {
            get { return _products; }
            set { _products = value; }
        }

        public static ProductModel GetProductModel()
        {
            ProductModel productModel = new ProductModel();
            productModel.Products = GetProducts();
            return productModel;
        }

        private static XmlAttribute GetNodeAttribute(XmlDocument doc, string attrName, string attrValue)
        {
            XmlAttribute attribute = doc.CreateAttribute(attrName);
            attribute.Value = attrValue.Encode();
            return attribute;
        }

        public static void UpdateProduct(string id, Product product)
        {
            string filePath = DataFilePath();
            XmlDocument doc = new XmlDocument();
            doc.Load(filePath);

            XmlNode node = null;
            if (String.IsNullOrEmpty(id))
            {
                XmlNode rootNode = doc.SelectSingleNode(@"/Products");
                node = doc.CreateElement("Product");
                rootNode.AppendChild(node);
            }
            else
            {
                node = doc.SelectSingleNode("/Products/Product[@id='" + id + "']");
            }
            node.Attributes.RemoveAll();
            node.Attributes.Append(GetNodeAttribute(doc, "id", product.Id));
            node.Attributes.Append(GetNodeAttribute(doc, "name", product.Name));

            string image = product.Image.Substring(product.Image.LastIndexOf("/")+1).Replace(IMAGE_FILE_EXTENSION, "").Encode();
            node.Attributes.Append(GetNodeAttribute(doc, "image", image));
            node.Attributes.Append(GetNodeAttribute(doc, "inventory", (product.Inventory >= 0 && product.Inventory <= 100 ? product.Inventory.ToString() : "0")));
            node.Attributes.Append(GetNodeAttribute(doc, "rating", (product.Rating >= 0 && product.Rating <= 5 ? String.Format("{0:#.##}", product.Rating) : "0.00")));
            node.Attributes.Append(GetNodeAttribute(doc, "buyurl", product.BuyUrl));
            node.Attributes.Append(GetNodeAttribute(doc, "wikiaurl", product.WikiaUrl));
            node.InnerText = product.Description.Encode();

            doc.Save(filePath);
        }

        public static void DeleteProduct(string id)
        {
            string filePath = HttpContext.Current.Server.MapPath(DATA_FILE_FOLDER + DATA_FILE);
            XmlDocument doc = new XmlDocument();
            doc.Load(filePath);

            XmlNode node = doc.SelectSingleNode("/Products/Product[@id='" + id + "']");
            if (node != null)
            {
                node.ParentNode.RemoveChild(node);
                doc.Save(filePath);
            }
        }

        public static Product GetProduct(string id)
        {
            string filePath = HttpContext.Current.Server.MapPath(DATA_FILE_FOLDER + DATA_FILE);
            XmlDocument doc = new XmlDocument();
            doc.Load(filePath);

            XmlNode node = doc.SelectSingleNode("/Products/Product[@id='" + id + "']");
            if (node != null)
            {
                Product product = new Product();
                product.Id = id;
                product.BuyUrl = (node.Attributes["buyurl"] != null ? node.Attributes["buyurl"].Value : "").Decode();
                product.WikiaUrl = (node.Attributes["wikiaurl"] != null ? node.Attributes["wikiaurl"].Value : "").Decode();
                product.Name = (node.Attributes["name"] != null ? node.Attributes["name"].Value : "").Decode();
                product.Image = (IMAGE_FILE_FOLDER.Replace("~", HttpContext.Current.Request.ApplicationPath) + "/" + (node.Attributes["image"] != null ? node.Attributes["image"].Value : "").Decode() + IMAGE_FILE_EXTENSION).Replace("//", "/");
                product.Inventory = Int32.Parse(node.Attributes["inventory"] != null ? node.Attributes["inventory"].Value : "0");
                product.Rating = Single.Parse(node.Attributes["rating"] != null ? node.Attributes["rating"].Value : "0.00");
                product.Description = node.InnerText == null ? "" : node.InnerText.Decode();
                return product;
            }
            else
                return null;

        }

        public static ProductCollection GetProducts()
        {
            string filePath = DataFilePath();
            ProductCollection products = new ProductCollection();
            if (File.Exists(filePath))
            {
                //Create a FileStream for the Config file
                FileStream fileReader = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);

                XPathDocument doc = new XPathDocument(fileReader);

                foreach (XPathNavigator nav in doc.CreateNavigator().Select("Products/Product"))
                {
                    Product product = GetProduct(nav);
                    if (product != null)
                        products.Add(product);
                }

                if (fileReader != null)
                    fileReader.Close();

            }
            return products;
        }

        private static Product GetProduct(XPathNavigator nav)
        {

            string id = nav.GetAttribute("id", "");
            if (String.IsNullOrEmpty(id)) return null;

            Product product = new Product();
            product.Id = id;
            product.BuyUrl = (!String.IsNullOrEmpty(nav.GetAttribute("buyurl", "")) ? nav.GetAttribute("buyurl", "") : "").Decode();
            product.WikiaUrl = (!String.IsNullOrEmpty(nav.GetAttribute("wikiaurl", "")) ? nav.GetAttribute("wikiaurl", "") : "").Decode();
            product.Name = (!String.IsNullOrEmpty(nav.GetAttribute("name", "")) ? nav.GetAttribute("name", "") : "").Decode();
            product.Image = (IMAGE_FILE_FOLDER.Replace("~",HttpContext.Current.Request.ApplicationPath) + "/" + (!String.IsNullOrEmpty(nav.GetAttribute("image","")) ? nav.GetAttribute("image", "") : "").Decode() + IMAGE_FILE_EXTENSION).Replace("//", "/");
            product.Inventory = Int32.Parse(!String.IsNullOrEmpty(nav.GetAttribute("inventory", "")) ? nav.GetAttribute("inventory", "") : "0");
            product.Rating = Single.Parse(!String.IsNullOrEmpty(nav.GetAttribute("rating", "")) ? nav.GetAttribute("rating", "") : "0.00");
            product.Description = nav.Value;
            return product;
        }

        public static void SaveProductModel(ProductModel productModel)
        {
            string filePath = DataFilePath();

            // Create a new Xml Serializer
            XmlSerializer ser = new XmlSerializer(typeof(ProductModel));
            if (File.Exists(filePath))
            {
                // make sure file is not read-only
                File.SetAttributes(filePath, FileAttributes.Normal);
            }
            FileStream fileWriter = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write);

            // Open up the file to serialize
            StreamWriter writer = new StreamWriter(fileWriter);

            // Serialize the Configuration
            ser.Serialize(writer, productModel);

            // Close the Writers
            writer.Close();
            fileWriter.Close();

        }

        private static string DataFilePath()
        {
            return HttpContext.Current.Server.MapPath(DATA_FILE_FOLDER + DATA_FILE);
        }

    }

    public static class StringHelper
    {
        public static string Decode(this string source)
        {
            return source.Replace("&amp;", "&").Replace("&quot;", "'").Replace("&gt;", ">").Replace("&lt;", "<");
        }

        public static string Encode(this string source)
        {
            return source.Replace("&", "&amp;").Replace("'", "&quot;").Replace(">", "&gt;").Replace("<", "&lt;");
        }
    }

}

